﻿using System;
using System.Collections.Generic;
using System.Text;

namespace AndersLiu.PE
{
    // ECMA335:P2,23.1.1
    // WinCrypt.h:
    //   #define ALG_CLASS_HASH                  (4 << 13)
    //   #define ALG_TYPE_ANY                    (0)
    //   #define ALG_SID_SHA1                    4
    //   #define CALG_SHA1               (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)
    public enum AssemblyHashAlgorithm : uint
    {
        None = 0x0000,
        MD5 = 0x8003,  // Reserved
        SHA1 = 0x8004,
    }

    public class AssemblyHashAlgorithmField : Field<AssemblyHashAlgorithm>
    {
        internal AssemblyHashAlgorithmField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override AssemblyHashAlgorithm ParseValue(byte[] rawData)
        {
            return (AssemblyHashAlgorithm)BitConverter.ToUInt32(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.2
    // CorHdr.h:CorAssemblyFlags
    [Flags]
    public enum AssemblyFlags : uint
    {
        PublicKey = 0x0001,     // The assembly ref holds the full (unhashed) public key.

        ProcessorArchitectureMask = 0x0070,     // Bits describing the processor architecture
        ProcessorArchitectureFullMask = 0x00F0,     // Bits describing the PA incl. Specified
        ProcessorArchitectureNone = 0x0000,     // Processor Architecture unspecified
        ProcessorArchitectureMsil = 0x0010,     // Processor Architecture: neutral (PE32)
        ProcessorArchitectureX86 = 0x0020,     // Processor Architecture: x86 (PE32)
        ProcessorArchitectureIa64 = 0x0030,     // Processor Architecture: Itanium (PE32+)
        ProcessorArchitectureAmd64 = 0x0040,     // Processor Architecture: AMD X64 (PE32+)
        ProcessorArchitectureSpecified = 0x0080,     // Propagate PA flags to AssemblyRef record
//        ProcessorArchitectureShift = 0x0004,     // NOT A FLAG, shift count in PA flags <--> index conversion

        EnableJitcompileTracking = 0x8000, // From "DebuggableAttribute".
        DisableJitcompileOptimizer = 0x4000, // From "DebuggableAttribute".

        Retargetable = 0x0100,     // The assembly can be retargeted (at runtime) to an
        //  assembly from a different publisher.
    }

    public class AssemblyFlagsField : Field<AssemblyFlags>
    {
        internal AssemblyFlagsField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override AssemblyFlags ParseValue(byte[] rawData)
        {
            return (AssemblyFlags)BitConverter.ToUInt32(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.3
    // Values for Culture
    // Not listed here

    // ECMA335:P2,23.1.4
    // CorHdr.h:CorEventAttr
    [Flags]
    public enum EventAttributes : ushort
    {
        SpecialName = 0x0200,     // event is special.  Name describes how.

        // Reserved flags for Runtime use only.
        ReservedMask = 0x0400,
        RtSpecialName = 0x0400,     // Runtime(metadata internal APIs) should check name encoding.
    }

    public class EventAttributesField : Field<EventAttributes>
    {
        internal EventAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override EventAttributes ParseValue(byte[] rawData)
        {
            return (EventAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.5
    // CorHdr.h:CorFieldAttr
    [Flags]
    public enum FieldAttributes : ushort
    {
        // member access mask - Use this mask to retrieve accessibility information.
        FieldAccessMask = 0x0007,
        PrivateScope = 0x0000,     // Member not referenceable.    // !!!!!!!!!!!!!!!!!!!!!! named 'CompilerControlled' in ECMA.
        Private = 0x0001,     // Accessible only by the parent type.
        FamAndAssem = 0x0002,     // Accessible by sub-types only in this Assembly.
        Assembly = 0x0003,     // Accessibly by anyone in the Assembly.
        Family = 0x0004,     // Accessible only by type and sub-types.
        FamOrAssem = 0x0005,     // Accessibly by sub-types anywhere, plus anyone in assembly.
        Public = 0x0006,     // Accessibly by anyone who has visibility to this scope.
        // end member access mask

        // field contract attributes.
        Static = 0x0010,     // Defined on type, else per instance.
        InitOnly = 0x0020,     // Field may only be initialized, not written to after init.
        Literal = 0x0040,     // Value is compile time constant.
        NotSerialized = 0x0080,     // Field does not have to be serialized when type is remoted.

        SpecialName = 0x0200,     // field is special.  Name describes how.

        // interop attributes
        PinvokeImpl = 0x2000,     // Implementation is forwarded through pinvoke.

        // Reserved flags for runtime use only.
        ReservedMask = 0x9500,    // !!!!!!!!!!!!!!!! not in ECMA
        RtSpecialName = 0x0400,     // Runtime(metadata internal APIs) should check name encoding.
        HasFieldMarshal = 0x1000,     // Field has marshalling information.
        HasDefault = 0x8000,     // Field has default.
        HasFieldRva = 0x0100,     // Field has RVA.
    }

    public class FieldAttributesField : Field<FieldAttributes>
    {
        internal FieldAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override FieldAttributes ParseValue(byte[] rawData)
        {
            return (FieldAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.6
    // CorHdr.h:CorFileFlags
    public enum FileAttributes : uint
    {
        ContainsMetaData = 0x0000,     // This is not a resource file
        ContainsNoMetaData = 0x0001,     // This is a resource file or other non-metadata-containing file
    }

    public class FileAttributesField : Field<FileAttributes>
    {
        internal FileAttributesField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override FileAttributes ParseValue(byte[] rawData)
        {
            return (FileAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.7
    // CorHdr.h:CorGenericParamAttr
    [Flags]
    public enum GenericParamAttributes : ushort
    {
        // Variance of type parameters, only applicable to generic parameters 
        // for generic interfaces and delegates
        VarianceMask = 0x0003,
        NonVariant = 0x0000,
        Covariant = 0x0001,
        Contravariant = 0x0002,

        // Special constraints, applicable to any type parameters
        SpecialConstraintMask = 0x001C,
        NoSpecialConstraint = 0x0000,
        ReferenceTypeConstraint = 0x0004,      // type argument must be a reference type
        NotNullableValueTypeConstraint = 0x0008,      // type argument must be a value type but not Nullable
        DefaultConstructorConstraint = 0x0010, // type argument must have a public default constructor
    }

    public class GenericParamAttributesField : Field<GenericParamAttributes>
    {
        internal GenericParamAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override GenericParamAttributes ParseValue(byte[] rawData)
        {
            return (GenericParamAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.8
    // CorHdr.h:CorPinvokeMap
    [Flags]
    public enum PInvokeAttributes : ushort
    {
        NoMangle = 0x0001,   // Pinvoke is to use the member name as specified.

        // Use this mask to retrieve the CharSet information.
        CharSetMask = 0x0006,
        CharSetNotSpec = 0x0000,
        CharSetAnsi = 0x0002,
        CharSetUnicode = 0x0004,
        CharSetAuto = 0x0006,

        BestFitMask = 0x0030,
        BestFitUseAssem = 0x0000,
        BestFitEnabled = 0x0010,
        BestFitDisabled = 0x0020,

        ThrowOnUnmappableCharMask = 0x3000,
        ThrowOnUnmappableCharUseAssem = 0x0000,
        ThrowOnUnmappableCharEnabled = 0x1000,
        ThrowOnUnmappableCharDisabled = 0x2000,

        SupportsLastError = 0x0040,   // Information about target function. Not relevant for fields.

        // None of the calling convention flags is relevant for fields.
        CallConvMask = 0x0700,
        CallConvWinapi = 0x0100,   // Pinvoke will use native callconv appropriate to target windows platform.
        CallConvCdecl = 0x0200,
        CallConvStdcall = 0x0300,
        CallConvThiscall = 0x0400,   // In M9, pinvoke will raise exception.
        CallConvFastcall = 0x0500,
    }

    public class PInvokeAttributesField : Field<PInvokeAttributes>
    {
        internal PInvokeAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override PInvokeAttributes ParseValue(byte[] rawData)
        {
            return (PInvokeAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.9
    // CorHdr.h:CorManifestResourceFlags
    [Flags]
    public enum ManifestResourceAttributes : uint
    {
        VisibilityMask = 0x0007,
        Public = 0x0001,     // The Resource is exported from the Assembly.
        Private = 0x0002,     // The Resource is private to the Assembly.
    }

    public class ManifestResourceAttributesField : Field<ManifestResourceAttributes>
    {
        internal ManifestResourceAttributesField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override ManifestResourceAttributes ParseValue(byte[] rawData)
        {
            return (ManifestResourceAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.10
    // CorHdr.h:CorMethodAttr
    [Flags]
    public enum MethodAttributes : ushort
    {
        // member access mask - Use this mask to retrieve accessibility information.
        MemberAccessMask = 0x0007,
        PrivateScope = 0x0000,     // Member not referenceable.
        Private = 0x0001,     // Accessible only by the parent type.
        FamAndAssem = 0x0002,     // Accessible by sub-types only in this Assembly.
        Assem = 0x0003,     // Accessibly by anyone in the Assembly.
        Family = 0x0004,     // Accessible only by type and sub-types.
        FamOrAssem = 0x0005,     // Accessibly by sub-types anywhere, plus anyone in assembly.
        Public = 0x0006,     // Accessibly by anyone who has visibility to this scope.
        // end member access mask

        // method contract attributes.
        Static = 0x0010,     // Defined on type, else per instance.
        Final = 0x0020,     // Method may not be overridden.
        Virtual = 0x0040,     // Method virtual.
        HideBySig = 0x0080,     // Method hides by name+sig, else just by name.

        // vtable layout mask - Use this mask to retrieve vtable attributes.
        VtableLayoutMask = 0x0100,
        ReuseSlot = 0x0000,     // The default.
        NewSlot = 0x0100,     // Method always gets a new slot in the vtable.
        // end vtable layout mask

        // method implementation attributes.
        CheckAccessOnOverride = 0x0200,     // Overridability is the same as the visibility.
        Abstract = 0x0400,     // Method does not provide an implementation.
        SpecialName = 0x0800,     // Method is special.  Name describes how.

        // interop attributes
        PInvokeImpl = 0x2000,     // Implementation is forwarded through pinvoke.
        UnmanagedExport = 0x0008,     // Managed method exported via thunk to unmanaged code.

        // Reserved flags for runtime use only.
        ReservedMask = 0xd000,
        RtSpecialName = 0x1000,     // Runtime should check name encoding.
        HasSecurity = 0x4000,     // Method has security associate with it.
        RequireSecObject = 0x8000,     // Method calls another method containing security code.
    }

    public class MethodAttributesField : Field<MethodAttributes>
    {
        internal MethodAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override MethodAttributes ParseValue(byte[] rawData)
        {
            return (MethodAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.11
    // CorHdr.h:CorMethodImpl
    [Flags]
    public enum MethodImplAttributes : ushort
    {
        // code impl mask
        CodeTypeMask = 0x0003,   // Flags about code type.
        IL = 0x0000,   // Method impl is IL.
        Native = 0x0001,   // Method impl is native.
        OptIL = 0x0002,   // Method impl is OPTIL
        Runtime = 0x0003,   // Method impl is provided by the runtime.
        // end code impl mask

        // managed mask
        ManagedMask = 0x0004,   // Flags specifying whether the code is managed or unmanaged.
        Unmanaged = 0x0004,   // Method impl is unmanaged, otherwise managed.
        Managed = 0x0000,   // Method impl is managed.
        // end managed mask

        // implementation info and interop
        ForwardRef = 0x0010,   // Indicates method is defined; used primarily in merge scenarios.
        PreserveSig = 0x0080,   // Indicates method sig is not to be mangled to do HRESULT conversion.

        InternalCall = 0x1000,   // Reserved for internal use.

        Synchronized = 0x0020,   // Method is single threaded through the body.
        NoInlining = 0x0008,   // Method may not be inlined.
        //MaxMethodImplVal = 0xffff,   // Range check value
    }

    public class MethodImplAttributesField : Field<MethodImplAttributes>
    {
        internal MethodImplAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override MethodImplAttributes ParseValue(byte[] rawData)
        {
            return (MethodImplAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.12
    // CorHdr.h:CorMethodSemanticsAttr
    [Flags]
    public enum MethodSemanticsAttributes : ushort
    {
        Setter = 0x0001,     // Setter for property
        Getter = 0x0002,     // Getter for property
        Other = 0x0004,     // other method for property or event
        AddOn = 0x0008,     // AddOn method for event
        RemoveOn = 0x0010,     // RemoveOn method for event
        Fire = 0x0020,     // Fire method for event
    }

    public class MethodSemanticsAttributesField : Field<MethodSemanticsAttributes>
    {
        internal MethodSemanticsAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override MethodSemanticsAttributes ParseValue(byte[] rawData)
        {
            return (MethodSemanticsAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.13
    // CorHdr.h:CorParamAttr
    [Flags]
    public enum ParamAttributes : ushort
    {
        In = 0x0001,     // Param is [In]
        Out = 0x0002,     // Param is [out]
        Optional = 0x0010,     // Param is optional

        // Reserved flags for Runtime use only.
        ReservedMask = 0xf000,
        HasDefault = 0x1000,     // Param has default value.
        HasFieldMarshal = 0x2000,     // Param has FieldMarshal.

        Unused = 0xcfe0,
    }

    public class ParamAttributesField : Field<ParamAttributes>
    {
        internal ParamAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override ParamAttributes ParseValue(byte[] rawData)
        {
            return (ParamAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.14
    // CorHdr.h:CorPropertyAttr
    [Flags]
    public enum PropertyAttributes : ushort
    {
        SpecialName = 0x0200,     // property is special.  Name describes how.

        // Reserved flags for Runtime use only.
        ReservedMask = 0xf400,
        RtSpecialName = 0x0400,     // Runtime(metadata internal APIs) should check name encoding.
        HasDefault = 0x1000,     // Property has default

        Unused = 0xe9ff,
    }

    public class PropertyAttributesField : Field<PropertyAttributes>
    {
        internal PropertyAttributesField(PEFile image, uint offset)
            : base(image, offset, 2)
        {
        }

        protected override PropertyAttributes ParseValue(byte[] rawData)
        {
            return (PropertyAttributes)BitConverter.ToUInt16(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }

    // ECMA335:P2,23.1.15
    // CorHdr.h:CorTypeAttr
    [Flags]
    public enum TypeAttributes : uint
    {
        // Use this mask to retrieve the type visibility information.
        VisibilityMask = 0x00000007,
        NotPublic = 0x00000000,     // Class is not public scope.
        Public = 0x00000001,     // Class is public scope.
        NestedPublic = 0x00000002,     // Class is nested with public visibility.
        NestedPrivate = 0x00000003,     // Class is nested with private visibility.
        NestedFamily = 0x00000004,     // Class is nested with family visibility.
        NestedAssembly = 0x00000005,     // Class is nested with assembly visibility.
        NestedFamAndAssem = 0x00000006,     // Class is nested with family and assembly visibility.
        NestedFamOrAssem = 0x00000007,     // Class is nested with family or assembly visibility.

        // Use this mask to retrieve class layout information
        LayoutMask = 0x00000018,
        AutoLayout = 0x00000000,     // Class fields are auto-laid out
        SequentialLayout = 0x00000008,     // Class fields are laid out sequentially
        ExplicitLayout = 0x00000010,     // Layout is supplied explicitly
        // end layout mask

        // Use this mask to retrieve class semantics information.
        ClassSemanticsMask = 0x00000060,    // !!!!!!!!!!!!ECMA gives 0x20, why 60????????
        Class = 0x00000000,     // Type is a class.
        Interface = 0x00000020,     // Type is an interface.
        // end semantics mask

        // Special semantics in addition to class semantics.
        Abstract = 0x00000080,     // Class is abstract
        Sealed = 0x00000100,     // Class is concrete and may not be extended
        SpecialName = 0x00000400,     // Class name is special.  Name describes how.

        // Implementation attributes.
        Import = 0x00001000,     // Class / interface is imported
        Serializable = 0x00002000,     // The class is Serializable.

        // Use tdStringFormatMask to retrieve string information for native interop
        StringFormatMask = 0x00030000,
        AnsiClass = 0x00000000,     // LPTSTR is interpreted as ANSI in this class
        UnicodeClass = 0x00010000,     // LPTSTR is interpreted as UNICODE
        AutoClass = 0x00020000,     // LPTSTR is interpreted automatically
        CustomFormatClass = 0x00030000,     // A non-standard encoding specified by CustomFormatMask
        CustomFormatMask = 0x00C00000,     // Use this mask to retrieve non-standard encoding information for native interop. The meaning of the values of these 2 bits is unspecified.

        // end string format mask

        BeforeFieldInit = 0x00100000,     // Initialize the class any time before first static field access.
        Forwarder = 0x00200000,     // This ExportedType is a type forwarder.    // !!!!!!!!!!!!! not in ECMA.

        // Flags reserved for runtime use.
        ReservedMask = 0x00040800,     // !!!!!!!!!!!!!!!! not in ECMA, but useful.
        RtSpecialName = 0x00000800,     // Runtime should check name encoding.
        HasSecurity = 0x00040000,     // Class has security associate with it.
    }

    public class TypeAttributesField : Field<TypeAttributes>
    {
        internal TypeAttributesField(PEFile image, uint offset)
            : base(image, offset, 4)
        {
        }

        protected override TypeAttributes ParseValue(byte[] rawData)
        {
            return (TypeAttributes)BitConverter.ToUInt32(rawData, 0);
        }

        protected override string GetValueString()
        {
            return EnumUtility.GetEnumStrig(this.Value);
        }
    }
}
